package cn.edu.scnu.socialapp.service.impl;

import cn.edu.scnu.socialapp.dao.mapper.ArticleMapper;
import cn.edu.scnu.socialapp.dos.Archives;
import cn.edu.scnu.socialapp.model.entity.Article;
import cn.edu.scnu.socialapp.model.entity.User;
import cn.edu.scnu.socialapp.model.vo.params.PageParams;
import cn.edu.scnu.socialapp.service.*;
import cn.edu.scnu.socialapp.utils.UserThreadLocal;
import cn.edu.scnu.socialapp.model.vo.*;
import cn.edu.scnu.socialapp.model.vo.params.ArticleParams;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private ThreadService threadService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private UserService userService;

    /**
     * 分页查询 文章列表
     *
     * @param pageParams
     * @return vo.Result
     */
    @Override
    public Result listArticle(PageParams pageParams) {
        Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
        IPage<Article> articleIPage = this.articleMapper.listArticle(
                page,
                pageParams.getYear(),
                pageParams.getMonth());// 注意将不足2位的Month字符串补全为2位，用于SQL查询
        return Result.success(copyList(articleIPage.getRecords(), true, true));
    }

    @Override
    public Result listArchives() {
        // select year(create_date) as year, month(create_date) as month, count(*) as count from blog_article group by year, month
        List<Archives> archivesList = articleMapper.listArchives();
        return Result.success(archivesList);
    }

    @Override
    public Result findArticleById(Long articleId) {
        /**
         * 1. 根据id查询 文章信息
         * 2. 根据bodyId和categoryid 去做关联查询
         */
        Article article = this.articleMapper.selectById(articleId);
        ArticleVo articleVo = copy(article, true, true, true, true);
        // 查看完文章之后，本应该直接做一个更新操作，更新时加写锁，阻塞其他的读操作，性能就会比较低
        // 更新 增加了此次请求的耗时 如果一旦更新出问题，不能影响查看文章的操作
        // 使用线程池 可以把更新操作扔到线程池中去执行 和主线程就不相关了
        threadService.updateArticleViewCount(article);
        return Result.success(articleVo);
    }

    @Override
    public Result publish(ArticleParams articleParams) {
        /**
         * 1. 发布文章 目的 构建Article对象
         * 2. 作者id  当前的登录用户
         */
        // 新建一个article对象
        Article article = new Article();
        // 将params中包含的信息注入对象
        article.setCreateTime(LocalDateTime.now());
        article.setMediaUrl(articleParams.getMedia_url());
        // 由于使用了当前用户信息，此接口需要加入到登录拦截之中
        User user = UserThreadLocal.get();
        article.setAuthorId(user.getUserId());
        article.setCommentCounts(0);
        article.setViewCounts(0);
        article.setContent(articleParams.getContent());
        // 执行插入操作后，mp会自动将id回写至article对象
        articleMapper.insert(article);
        deleteCaches("listArticle*");
        Map<String, String> resultMap = new HashMap<String, String>();
        resultMap.put("id", article.getArticleId().toString());
        return Result.success(resultMap);
    }

    @Override
    public Result edit(ArticleParams articleParams) {
        // 修改文章
        Article article = articleMapper.selectById(articleParams.getArticle_id());
        article.setContent(articleParams.getContent());
        article.setMediaUrl(articleParams.getMedia_url());
        int res = articleMapper.updateById(article);
        if (res != 0) {
            deleteCaches("*" + DigestUtils.md5Hex(article.getArticleId().toString()));
            deleteCaches("listArticle*");
            Map<String, String> resultMap = new HashMap<String, String>();
            resultMap.put("id", article.getArticleId().toString());
            return Result.success(resultMap);
        } else {
            return Result.fail(ErrorCode.EDIT_FAILED.getCode(), ErrorCode.EDIT_FAILED.getMessage());
        }
    }

    @Override
    public Result deleteArticleById(Long articleId) {
        int res = articleMapper.deleteById(articleId);
        if (res != 0 ) {
            deleteCaches("*" + DigestUtils.md5Hex(articleId.toString()));
            redisTemplate.delete("newArticles:");
            redisTemplate.delete("hotArticles:");
            deleteCaches("listArticle*");
            return Result.success(null);
        } else {
            return Result.fail(ErrorCode.DELETE_FAILED.getCode(), ErrorCode.DELETE_FAILED.getMessage());
        }
    }

    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor) {
        List<ArticleVo> articleVoList = new ArrayList<ArticleVo>();
        for (Article record : records) {
            articleVoList.add(copy(record, isTag, isAuthor, false, false));
        }
        return articleVoList;

    }

    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor, boolean isBody, boolean isCategory) {
        List<ArticleVo> articleVoList = new ArrayList<ArticleVo>();
        for (Article record : records) {
            articleVoList.add(copy(record, isTag, isAuthor, isBody, isCategory));
        }
        return articleVoList;

    }

    private ArticleVo copy(Article article, boolean isTag, boolean isAuthor, boolean isBody, boolean isCategory) {
        ArticleVo articleVo = new ArticleVo();
        //BeanUtils.copyProperties用法   https://blog.csdn.net/Mr_linjw/article/details/50236279
        BeanUtils.copyProperties(article, articleVo);
        articleVo.setCreateDate(new DateTime(article.getCreateTime()).toString("yyyy-MM-dd HH:mm"));
        if (isAuthor) {
            //拿到作者id
            UserVo userVo = new UserVo();
            User user = userService.findUserByUserId(article.getAuthorId());
            if (user != null) {
                BeanUtils.copyProperties(user, userVo);
            } else {
                articleVo.setAuthor(null);
            }
            articleVo.setAuthor(userVo);
        }
        return articleVo;

    }

    private void deleteCaches(String regex) {
        System.out.println("regex:" + regex);
        Set<String> keys = redisTemplate.keys(regex);
        Long delete = redisTemplate.delete(keys);
        System.out.println("delete:" + delete);
    }
}
